package com.ruben;/**
 * @ClassName: MybatisPlusDemo
 * @Date: 2020/11/9 0009 20:51
 * @Description:
 */

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.BeanUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.github.javafaker.Faker;
import com.ruben.dao.MpUserMapper;
import com.ruben.pojo.po.UserPO;
import com.ruben.sakila.entity.Film;
import com.ruben.sakila.entity.Language;
import com.ruben.sakila.mapper.FilmMapper;
import com.ruben.sakila.mapper.FilmTextMapper;
import com.ruben.sakila.mapper.LanguageMapper;
import com.ruben.sakila.service.IFilmService;
import com.ruben.service.MpUserService;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.test.annotation.Rollback;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.security.SecureRandom;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.Year;
import java.time.ZoneId;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @ClassName: MybatisPlusDemo
 * @Description: 我还没有写描述
 * @Date: 2020/11/9 0009 20:51
 * *
 * @author: <achao1441470436@gmail.com>
 * @version: 1.0
 * @since: JDK 1.8
 */
@SpringBootTest
@Rollback(false)
public class MybatisPlusDemo {

    public static ExecutorService executor = Executors.newFixedThreadPool(100000);
    @Resource
    private FilmMapper filmMapper;
    @Resource
    private IFilmService filmService;
    @Resource
    private FilmTextMapper filmTextMapper;
    @Resource
    private MpUserMapper mpUserMapper;
    @Resource
    private MpUserService mpUserService;
    @Resource
    private LanguageMapper languageMapper;

    @Test
    public void insert() {
        AtomicInteger index = new AtomicInteger(5);
        List<UserPO> userList = Stream.generate(() -> UserPO.builder()
                .id(index.getAndIncrement())
                .username(Faker.instance(Locale.ENGLISH).name().lastName())
                .password(new BCryptPasswordEncoder().encode("123456"))
                .build()).limit(200).collect(Collectors.toList());
        mpUserService.saveBatch(userList);
    }

    @Test
    public void delete() {
        mpUserMapper.delete(Wrappers.lambdaQuery(new UserPO(888)));
    }

    @Test
    public void test() {
        IPage<UserPO> page = mpUserMapper.selectPage(new Page<>(1, 2), Wrappers.lambdaQuery(UserPO.builder().build()));
        System.out.println(page);
        LambdaQueryWrapper<UserPO> wrapper = Wrappers.lambdaQuery(UserPO.builder().build());
        // 取得用户ids
        List<Integer> userIds = page.getRecords().stream().map(UserPO::getId).collect(Collectors.toList());
        // 根据ids用IN查询
        wrapper.in(UserPO::getId, userIds)
                // 并且
                .and(w -> w.like(UserPO::getUsername, "achao").or(wr -> wr.like(UserPO::getUsername, "Achao")));
        page = mpUserMapper.selectPage(new Page<>(1, 2), wrapper);
        System.out.println(page);
    }

    @Test
    public void list() {
        mpUserService.list(Wrappers.lambdaQuery(UserPO.builder().username("hino").build()));
        mpUserMapper.selectList(Wrappers.lambdaQuery(UserPO.builder().username("ruben").build()));
    }

    @Test
    public void insertTestData() {
        for (int i = 0; i < 1000000; i++) {
            Faker faker = Faker.instance(Locale.CHINA);
            Date birthday = faker.date().birthday();
            Instant instant = birthday.toInstant();
            LocalDateTime localDateTime = LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
            Film film = Film.builder()
                    .title(faker.name().title())
                    .description(faker.lorem().sentence())
                    .releaseYear(Year.from(localDateTime))
                    .languageId(7)
                    .originalLanguageId(7)
                    .rentalRate(new SecureRandom().doubles(0.99D, 5.00D)
                            .boxed()
                            .findAny()
                            .map(BigDecimal::new)
                            .orElse(BigDecimal.ONE))
                    .length(new SecureRandom().ints(46, 186).findAny().orElse(46))
                    .replacementCost(new SecureRandom().doubles(9.99D, 30.00D)
                            .boxed()
                            .findAny()
                            .map(BigDecimal::new)
                            .orElse(BigDecimal.TEN))
                    .rating("G")
                    .specialFeatures("Deleted Scenes")
                    .rentalDuration(new SecureRandom().ints(3, 8).findAny().orElse(3))
                    .build();
            filmMapper.insert(film);
        }
    }

    @Test
    public void selectTest() {
        long startTime = System.nanoTime();
        List<Map<String, Object>> maps = filmMapper.selectFilmAndLanguage();
        long endTime = System.nanoTime();
        System.out.println("耗时：" + ((endTime - startTime) / (1000.0 * 1000.0)) + " ms");        // 单个 LEFT JOIN 耗时：33457.8317 ms 两个 LEFT JOIN 耗时：37053.9295 ms 加索引后 耗时：35314.184 ms
    }

    @Test
    public void singleTable() throws ExecutionException, InterruptedException {
        long startTime = System.nanoTime();
        List<Film> films = filmMapper.selectList(Wrappers.lambdaQuery());
        List<Integer> languageIds = films.parallelStream()
                .map(Film::getLanguageId)
                .distinct()
                .collect(Collectors.toList());
        final Map<Integer, Language> languageMap = languageMapper.selectList(Wrappers.lambdaQuery(Language.builder()
                .build()).in(Language::getLanguageId, languageIds))
                .parallelStream()
                .collect(Collectors.toMap(Language::getLanguageId, Function.identity(), (v1, v2) -> v2));
        List<Map<String, Object>> collect = films.stream().map(film -> {
            Map<String, Object> map = BeanUtils.beanToMap(film);
            Optional.ofNullable(film)
                    .map(Film::getLanguageId)
                    .map(languageMap::get)
                    .map(BeanUtils::beanToMap)
                    .ifPresent(map::putAll);
            return map;
        }).collect(Collectors.toList());
        long endTime = System.nanoTime();
        System.out.println("耗时：" + ((endTime - startTime) / (1000.0 * 1000.0)) + " ms");        // 两次查询表 耗时：22289.5385 ms 第二张表再查一次 耗时：23362.9739 ms
    }

    @Test
    public void cycleTest() {
        long startTime = System.nanoTime();
        List<Film> films = filmMapper.selectList(Wrappers.lambdaQuery());
        List<Map<String, Object>> collect = films.stream().map(film -> {
            Language language = languageMapper.selectById(film.getLanguageId());
            Language language1 = languageMapper.selectById(film.getLanguageId());
            Map<String, Object> map = BeanUtils.beanToMap(film);
            map.putAll(BeanUtils.beanToMap(language));
            map.putAll(BeanUtils.beanToMap(language1));
            return map;
        }).collect(Collectors.toList());
        long endTime = System.nanoTime();
        System.out.println("耗时：" + ((endTime - startTime) / (1000.0 * 1000.0)) + " ms");        // 循环调用数据库 耗时：302577.2408 ms 第二张表再查一次 耗时：421330.6798 ms
    }


    @Test
    public void singleTableTwice() throws ExecutionException, InterruptedException {
        long startTime = System.nanoTime();
        List<Film> films = filmMapper.selectList(Wrappers.lambdaQuery());
        List<Integer> languageIds = films.parallelStream()
                .map(Film::getLanguageId)
                .distinct()
                .collect(Collectors.toList());
        CompletableFuture<Map<Integer, Language>> languageMapFuture = CompletableFuture.supplyAsync(() -> languageMapper
                .selectList(Wrappers.lambdaQuery(Language.builder().build()).in(Language::getLanguageId, languageIds))
                .parallelStream()
                .collect(Collectors.toMap(Language::getLanguageId, Function.identity(), (v1, v2) -> v2)));
        CompletableFuture<Map<Integer, Language>> languageMapFuture1 = CompletableFuture.supplyAsync(() -> languageMapper
                .selectList(Wrappers.lambdaQuery(Language.builder().build()).in(Language::getLanguageId, languageIds))
                .parallelStream()
                .collect(Collectors.toMap(Language::getLanguageId, Function.identity(), (v1, v2) -> v2)));
        CompletableFuture.allOf(languageMapFuture, languageMapFuture1).get();
        Map<Integer, Language> languageMap = languageMapFuture.get();
        Map<Integer, Language> languageMap1 = languageMapFuture1.get();
        List<Map<String, Object>> collect = films.stream().map(film -> {
            Map<String, Object> map = BeanUtils.beanToMap(film);
            Optional.ofNullable(film)
                    .map(Film::getLanguageId)
                    .map(languageMap::get)
                    .map(BeanUtils::beanToMap)
                    .ifPresent(map::putAll);
            Optional.ofNullable(film)
                    .map(Film::getLanguageId)
                    .map(languageMap1::get)
                    .map(BeanUtils::beanToMap)
                    .ifPresent(map::putAll);
            return map;
        }).collect(Collectors.toList());
        long endTime = System.nanoTime();
        System.out.println("耗时：" + ((endTime - startTime) / (1000.0 * 1000.0)) + " ms");        // 两次查询表 耗时：22289.5385 ms 第二张表再查一次 耗时：23362.9739 ms

        filmMapper.selectList(Wrappers.lambdaQuery(Film.builder().build()).in(Film::getLanguageId, languageIds));
    }


    @Test
    public void deleteTest() {
        List<Film> films = filmMapper.selectList(Wrappers.lambdaQuery(Film.builder().build()).last("LIMIT 2"));
//        films.stream().findFirst().map(Film::getFilmId).ifPresent(filmMapper::deleteById);
    }

}
